package com.zhuoyue;

import com.zhuoyue.utils.PassthroughCode;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *
 * 线程阻塞读取消息，触发回调
 *
 * @author Created by mr.liang
 */
public class ReadThreadManagement implements Runnable {

    private ConnectionManagement connectionManagement;

    private Thread currentThread;

    private ClientConfig clientConfig;

    private Client client;

    private final AtomicInteger state = new AtomicInteger();
    private final int INIT = -1;
    private final int RUN = 1;
    private final int STOP= 2;


    public ReadThreadManagement(ClientConfig clientConfig,Client client,ConnectionManagement connectionManagement) {
        this.clientConfig = clientConfig;
        this.connectionManagement = connectionManagement;
        this.client = client;

        state.set(INIT);
    }



    @Override
    public void run() {
        if(!state.compareAndSet(INIT,RUN)){
            return ;
        }
        currentThread = Thread.currentThread();

        try {
            //作为一个缓存的容器
            ByteArrayOutputStream bao = new ByteArrayOutputStream();

            int len;
            byte[] temp = new byte[1024];
            while ((len = connectionManagement.read(temp)) != -1) {
                bao.write(temp, 0, len);

                //解码

                //理论上可以通过java 反射拿出array而不是copy,但是太麻烦了。
                byte[] bytes = bao.toByteArray();

                int index = 0;
                if (bytes.length > temp.length) {
                    index = bytes.length - temp.length - 1;
                }

                //等于2有可能服务端发一个空byte
                if (bytes.length - index < 2) {
                    continue;
                }

                //找到0xff、0xff的序列
                List<Integer> endIndexs = new ArrayList<>();
                byte[] tem = new byte[2];
                for (int i = index; i < bytes.length -1; ) {
                    tem[0] = bytes[i];
                    tem[1] = bytes[i + 1];

                    if (tem[1] == (byte) 0XFF) {
                        if (tem[0] == (byte) 0XFF) {
                            endIndexs.add(i);
                            i += 2;
                        } else {
                            i++;
                        }
                    } else {
                        i += 2;
                    }
                }


                //分离单一的包
                int startIndex = 0;
                for (int i = 0; i < endIndexs.size(); i++) {
                    Integer endIndex = endIndexs.get(i);
                    byte[] tempByte = new byte[endIndex - startIndex];
                    System.arraycopy(bytes, startIndex, tempByte, 0, tempByte.length);
                    startIndex = endIndex + 2;

                    clientConfig.getThreadPoolExecutor().execute(() ->
                        client.callback(new String(PassthroughCode.decode(tempByte), clientConfig.getEncodeCharset()))
                    );
                }

                //剩下缓存的字节数组
                bao.reset();
                if (startIndex - 1 != bytes.length) {
                    byte[] tempByte = new byte[bytes.length - startIndex];
                    System.arraycopy(bytes, startIndex, tempByte, 0, tempByte.length);
                    bao.write(tempByte);
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        state.compareAndSet(RUN,STOP);
    }


    public void start(){
        new Thread(this).start();
    }


    public boolean cancal(){
        if(state.get() == STOP || state.compareAndSet(INIT,STOP)){
            return true;
        }

        int sleepTime = 1;
        int sleeps = 0;

        while (true){//参考自java.nio.Bits.reserveMemory方法
            currentThread.interrupt();
            if(isStop()){
                return true;
            }

            if (sleeps >= 9){//最多试9次，9次之后仍然无法收回，说明真的而无法收回,相当于2048毫秒，
                return isStop();
            }

            try {
                Thread.sleep(sleepTime);
                sleepTime <<= 1;
                sleeps++;
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    public boolean isStop(){
        return state.get() == STOP;
    }

}
